﻿using EFCoreDemo;
using EFCoreDemo.Database;
using EFCoreDemo.Entity;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace EFCoreDemo.Repository
{
    public class BaseRepository<T> : BaseQueryable<T>, IRepository<T> where T : class, IEntity
    {
        public BaseRepository(DatabaseContext context) : base(context)
        {
        }
        public T Add(T entity)
        {
            if (entity.Id == 0)
            {
                entity.Id = IdGenerate.NetLongId();
            }
            var entityEntry = context.Entry(entity);
            entityEntry.State = EntityState.Added;
            return entityEntry.Entity;
        }
        public virtual List<T> AddRange(List<T> entitys) 
        {
            foreach (var entity in entitys)
            {
                if (entity.Id == 0)
                {
                    entity.Id = IdGenerate.NetLongId();
                }
            }
            context.AddRange(entitys);
            return entitys;
        }
        public T Update(T entity)
        {
            if (!context.ChangeTracker.Entries<T>().Any(v => v.Entity.Id == entity.Id))
            {
                var entityEntry = context.Entry(entity);
                entityEntry.State = EntityState.Modified;
                return entityEntry.Entity;
            }
            else
            {
                var entityEntry = context.ChangeTracker.Entries<T>().FirstOrDefault(v => v.Entity.Id == entity.Id);
                foreach (var prop in typeof(T).GetProperties())
                {
                    entityEntry.Property(prop.Name).CurrentValue = prop.GetValue(entity, null);
                }
                return entityEntry.Entity;
            }
        }
        public void Delete(T entity)
        {
            if (entity is IHasSoftDelete)
            {
                var entityEntry = context.Entry(entity);
                entityEntry.Property("IsDeleted").CurrentValue = true;
                entityEntry.State = EntityState.Modified;
            }
            else
            {
                context.Entry(entity).State = EntityState.Deleted;
            }
        }
        public void Delete(long id)
        {
            var entity = Queryable.FirstOrDefault(x => x.Id == id);
            if (entity != null)
                Delete(entity);
        }
        public virtual int DeleteRange(IEnumerable<T> delDatas)
        {
            var datas = delDatas.ToList();
            if (typeof(T).IsAssignableFrom(typeof(IHasSoftDelete)))
            {
                foreach (var entity in datas)
                {
                    context.Entry(entity).Property("IsDeleted").CurrentValue = true;
                    context.Entry(entity).State = EntityState.Modified;
                }
            }
            else
            {
                context.RemoveRange(datas);
            }
            return datas.Count;
        }
        public virtual int DeleteRange(Expression<Func<T, bool>> predicate)
        {
            return DeleteRange(Queryable.Where(predicate));
        }

        public T Get(long id)
        {
            return Queryable.FirstOrDefault(v => v.Id == id);
        }

        public int ExecuteSql(FormattableString sql)
        {
            return context.Database.ExecuteSqlCommand(sql);
        }

        public int ExecuteSql(string sql)
        {
            return context.Database.ExecuteSqlCommand(sql);
        }

    }
}
